﻿//AcademicPlanner - course registration planning web app.
//Copyright (C) 2009  Boubacar Diallo

//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either version 2
//of the License, or (at your option) any later version.

//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.

//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.Web.Routing;

namespace AcademicPlanner.Framework.Helpers
{
	/// <summary>
	/// HtmlHelperExtensions provides static helper methods for
	/// creating lightweight html tags and controls.
	/// The methods are extensions to the ASP.NET MVC <c>HtmlHelper</c>.
	/// </summary>
	/// <since>1.0</since>
	public static class HtmlHelperExtensions
	{
		private static int htmlIdCounter = 0;
		/// <summary>
		/// Creates a html label for a form field. 
		/// </summary>
		/// <param name="helper">The ASP.NET MVC <c>HtmlHelper</c> being extended.</param>
		/// <param name="pFor">The html id of the field the label is for.</param>
		/// <param name="pLabel">The text of the label.</param>
		/// <param name="pRequired">Whether the field being labeled is required or not.</param>
		/// <returns>The html string for the label.</returns>
		/// <since>1.0</since>
		public static string Label(this HtmlHelper helper, string pFor, string pLabel, bool pRequired)
		{
			StringBuilder vBuilder = new StringBuilder();
			string vLabel = string.IsNullOrEmpty(pLabel) ? pFor : pLabel;

			vBuilder.Append("<label for=\"");
			vBuilder.Append(pFor);
			vBuilder.Append("\">");
			vBuilder.Append(vLabel);
			if (pRequired) vBuilder.Append(" <span class=\"required-marker\">*</span>");
			vBuilder.Append("</label>");

			return vBuilder.ToString();
		}

		/// <summary>
		/// Creates a html label for a form field.
		/// This method is aconvenience overload of <see cref="M:Label(HtmlHelper, string, string, bool)"/>
		/// with the fourth parameter <c>false</c>.
		/// </summary>
		/// <param name="helper">The ASP.NET MVC <c>HtmlHelper</c> being extended.</param>
		/// <param name="pFor">The html id of the field the label is for.</param>
		/// <param name="pLabel">The text of the label.</param>
		/// <returns>The html string for the label.</returns>
		/// <since>1.0</since>
		public static string Label(this HtmlHelper helper, string pFor, string pLabel)
		{
			return Label(helper, pFor, pLabel, false);
		}

		/// <summary>
		/// Creates a html label for a form field.
		/// This method is aconvenience overload of <see cref="M:Label(HtmlHelper, string, string)"/>
		/// with the third parameter <c>null</c>.
		/// </summary>
		/// <param name="helper">The ASP.NET MVC <c>HtmlHelper</c> being extended.</param>
		/// <param name="pFor">The html id of the field the label is for.</param>
		/// <returns>The html string for the label.</returns>
		/// <since>1.0</since>
		public static string Label(this HtmlHelper helper, string pFor)
		{
			return Label(helper, pFor, null);
		}

		/// <summary>
		/// Creates a html input of type text with size of 20 and maxlength
		/// of 100.
		/// </summary>
		/// <param name="helper">The ASP.NET MVC <c>HtmlHelper</c> being extended.</param>
		/// <param name="pName">The name of the input field.</param>
		/// <param name="pValue">The value of the input field.</param>
		/// <returns>The html string for the input of type text.</returns>
		/// <since>1.0</since>
		public static string TextField(this HtmlHelper helper, string pName, string pValue)
		{
			return helper.TextBox(pName, pValue, new { size = 20, maxlength = 100 });
		}

		/// <summary>
		/// Creates a html input of type password with size of 20.
		/// </summary>
		/// <param name="helper">The ASP.NET MVC <c>HtmlHelper</c> being extended.</param>
		/// <param name="pName">The name of the input field.</param>
		/// <param name="pValue">The value of the input field.</param>
		/// <returns>The html string for the input of type password.</returns>
		/// <since>1.0</since>
		public static string PasswordField(this HtmlHelper helper, string pName, string pValue)
		{
			return helper.Password(pName, pValue, new { size = 20, maxlength = 20 });
		}

		///// <summary>
		///// Creates a html input of type password with size of 20.
		///// </summary>
		///// <param name="helper">The ASP.NET MVC <c>HtmlHelper</c> being extended.</param>
		///// <param name="pName">The name of the input field.</param>
		///// <param name="pValue">The value of the input field.</param>
		///// <param name="pHtmlOptions"></param>
		///// <returns>The html string for the input of type password.</returns>
		///// <since>1.0</since>
		//public static string PasswordField(this HtmlHelper helper, string pName, string pValue, object pHtmlOptions)
		//{
		//    return helper.Password(pName, 20, pValue, pHtmlOptions);
		//}

		///// <summary>
		///// Creates a html input of type text with size of 20 and maxlength
		///// of 100.
		///// </summary>
		///// <param name="helper">The ASP.NET MVC <c>HtmlHelper</c> being extended.</param>
		///// <param name="pName">The name of the input field.</param>
		///// <param name="pValue">The value of the input field.</param>
		///// <param name="pHtmlOptions">An anonymous object of extra html attributes.</param>
		///// <returns>The html string for the input of type text.</returns>
		///// <since>1.0</since>
		//public static string TextField(this HtmlHelper helper, string pName, string pValue, object pHtmlOptions)
		//{
		//    return helper.TextBox(pName, pValue, 20, 100, pHtmlOptions);
		//}

		///// <summary>
		///// Creates a html submit button.
		///// </summary> 
		///// <remarks>
		///// This method is a convenience overload of <see cref="M:SubmitButton"/>.
		///// </remarks>
		///// <param name="helper">The ASP.NET MVC <c>HtmlHelper</c> being extended.</param>
		///// <param name="pName">The name of the submit button.</param>
		///// <param name="pText">The text of the submit button.</param>
		///// <returns>The html string for the submit button.</returns>
		///// <seealso cref="M:SubmitButton"/>
		///// <since>1.0</since>
		//public static string SubmitButton(this HtmlHelper helper, string pName, string pText)
		//{
		//    return SubmitButton(helper, pName, pText, "");
		//}

		/// <summary>
		/// Creates a html submit button.
		/// </summary>
		/// <param name="helper">The ASP.NET MVC <c>HtmlHelper</c> being extended.</param>
		/// <param name="pName">The name of the submit button.</param>
		/// <param name="pText">The text of the submit button.</param>
		/// <param name="pExtra">Extra html attributes.</param>
		/// <returns>The html string for the submit button.</returns>
		/// <since>1.0</since>
		public static string SubmitButton(this HtmlHelper helper, string pName, string pText, string pExtra)
		{
			var vId = pName+(htmlIdCounter++).ToString();
			var vFormat = "<input class=\"submit button\" type=\"submit\" name=\"{0}\" value=\" {1} \" {2} id=\"{3}\" /><script>gDomReadyQueue.push('gFormsCtrl.makeSubmitButton(\"{4}\");');</script>";
			var rButton = string.Format(vFormat, pName, pText, pExtra, vId, vId);

			return rButton;
		}

		/// <summary>
		/// Creates a html button for cancelling an action.
		/// </summary>
		/// <remarks>
		/// This methods registers a js script that calls gFormsCtrl.makeCancelButton.
		/// </remarks>
		/// <param name="helper">The ASP.NET MVC <c>HtmlHelper</c> being extended.</param>
		/// <param name="pName">The name of the button.</param>
		/// <param name="pText">The text of the button.</param>
		/// <param name="pExtra">Extra html attributes.</param>
		/// <returns>The html string for the button.</returns>
		/// <since>1.0</since>
		public static string CancelButton(this HtmlHelper helper, string pName, string pText, string pExtra)
		{
			var vId = pName + (htmlIdCounter++).ToString();
			var vCancelUrl = ""; //	TODO: IF REFERER IS OTHER DOMAIN SET URL TO HOME PAGE
			var vFormat = "<input class=\"button\" type=\"button\" name=\"{0}\" value=\" {1} \" {2} id=\"{3}\" /><script>gDomReadyQueue.push('gFormsCtrl.makeCancelButton(\"{4}\", \"{5}\");');</script>";
			var rButton = string.Format(vFormat, pName, pText, pExtra, vId, vId, vCancelUrl);

			return rButton;
		}

		/// <summary>
		/// Creates a fancy html button.
		/// </summary> 
		/// <remarks>
		/// This method registers a js script that calls gFormsCtrl.makePushButton.
		/// </remarks>
		/// <param name="helper">The ASP.NET MVC <c>HtmlHelper</c> being extended.</param>
		/// <param name="pName">The name of the button.</param>
		/// <param name="pText">The text of the button.</param>
		/// <param name="pJsCallback">
		/// The name of the js function to call after creation of the button on the client; the button object is passed to it.
		/// </param>
		/// <param name="pExtra">Extra html attributes.</param>
		/// <returns>The html string for the button.</returns>
		/// <since>1.0</since>
		public static string PushButton(this HtmlHelper helper, string pName, string pText, string pJsCallback, string pExtra)
		{
			var vId = pName + (htmlIdCounter++).ToString();
			var vFormat = "<input class=\"button\" type=\"button\" name=\"{0}\" value=\" {1} \" {2} id=\"{3}\" /><script>gDomReadyQueue.push('gFormsCtrl.makePushButton(\"{4}\", \"{5}\");');</script>";
			var rButton = string.Format(vFormat, pName, pText, pExtra, vId, vId, pJsCallback);

			return rButton;
		}

		/// <summary>
		/// Generates a html image tag.
		/// </summary>
		/// <remarks>
		/// This method is a convenience overload of 
		/// <see cref="M:Image(HtmlHelper, string, string, object)"/>
		/// with the fourth parameter set to <c>new {}</c>.
		/// </remarks>
		/// <param name="helper">The ASP.NET MVC <c>HtmlHelper</c> being extended.</param>
		/// <param name="pUrl">The url to the actual image.</param>
		/// <param name="pAlt">The html attribute alt for the image tag.</param>
		/// <returns>The html string for the image tag.</returns>
		/// <since>1.0</since>
		public static string Image(this HtmlHelper helper, string pUrl, string pAlt)
		{
			return Image(helper, pUrl, pAlt, new { });
		}

		/// <summary>
		/// Generates a html image tag.
		/// </summary>
		/// <remarks>
		/// This method is a convenience overload of <see cref="M:Image(string, string, object)"/>
		/// with the third parameter set to <c>new { }</c>
		/// </remarks>
		/// <param name="pUrl">The url to the image.</param>
		/// <param name="pAlt">The html attributes title and alt for the image tag.</param>
		/// <returns>The html string for the image tag.</returns>
		/// <since>1.0</since>
		public static string Image(string pUrl, string pAlt)
		{
			return Image(pUrl, pAlt, new { });
		}

		/// <summary>
		/// Generates a html image tag.
		/// </summary>
		/// <remarks>
		/// This method relies on <see cref="M:Image(string, string, object)"/>
		/// </remarks>
		/// <param name="helper">The ASP.NET MVC <c>HtmlHelper</c> being extended.</param>
		/// <param name="pUrl">The url to the image.</param>
		/// <param name="pTitle">The html attributes title and alt for the image tag.</param>
		/// <param name="pAttrs">Extra html attributes.</param>
		/// <returns>The html string for the image tag.</returns>
		/// <since>1.0</since>
		public static string Image(this HtmlHelper helper, string pUrl, string pTitle, object pAttrs)
		{
			return Image(pUrl, pTitle, pAttrs);
		}

		/// <summary>
		/// Generates a html image tag.
		/// </summary>
		///  <param name="pUrl">The url to the actual image.</param>
		/// <param name="pTitle">The html attributes title and alt for the image tag.</param>
		/// <param name="pAttrs">Extra html attributes.</param>
		/// <returns>The html string for the image tag.</returns>
		/// <since>1.0</since>
		public static string Image(string pUrl, string pTitle, object pAttrs)
		{
			var vFormat = "<img src=\"{0}\" alt=\"{1}\" title=\"{2}\" {3} />";
			var vExtra = pAttrs.ToAttributeList();
			var rImg = string.Format(vFormat, pUrl, pTitle, pTitle, vExtra);

			return rImg;
		}

		/// <summary>
		/// Creates a html break tag for the specified number
		/// of times.
		/// </summary>
		/// <param name="htmler">The ASP.NET MVC <c>HtmlHelper</c> being extended.</param>
		/// <param name="num">The number of break tags to create.</param>
		/// <returns>The html string for the break tags.</returns>
		/// <since>1.0</since>
		public static string Break(this HtmlHelper htmler, int num)
		{
			string rVal = "";

			if (num <= 0) return rVal;
			if (num > 10) num = 10;

			for (var i = 0; i < num; i++)
			{
				rVal += "<br />";
			}

			return rVal;
		}

		/// <summary>
		/// Creates a html break tag. This method is a convenience
		/// overload of <see cref="M:Break(HtmlHelper, int)"/> with
		/// the second parameter set to <c>1</c>.
		/// </summary>
		/// <param name="htmler">The ASP.NET MVC <c>HtmlHelper</c> being extended.</param>
		/// <returns>The html string for the break tag.</returns>
		/// <since>1.0</since>
		public static string Break(this HtmlHelper htmler)
		{
			return Break(htmler, 1);
		}

		/// <summary>
		/// Creates a html break with css class "clearFloat".
		/// </summary>
		/// <param name="htmler">The ASP.NET MVC <c>HtmlHelper</c> being extended.</param>
		/// <returns>The html string for the break tag.</returns>
		/// <since>1.0</since>
		public static string ClearBreak(this HtmlHelper htmler)
		{
			return "<br class=\"clearFloat\" />";
		}

		/// <summary>
		/// Creates <c>"&amp;nbsp;"</c>s for the specified number of times.
		/// </summary>
		/// <param name="htmler">The ASP.NET MVC <c>HtmlHelper</c> being extended.</param>
		/// <param name="num">The number of <c>"&amp;nbsp;"</c>s to create.</param>
		/// <returns>The html string for the <c>"&amp;nbsp;"</c>s.</returns>
		/// <since>1.0</since>
		public static string NBS(this HtmlHelper htmler, int num)
		{
			string rVal = "";

			if (num <= 0) return rVal;
			if (num > 10) num = 10;

			for (var i = 0; i < num; i++)
			{
				rVal += "&nbsp;";
			}

			return rVal;
		}

		/// <summary>
		/// Creates a <c>"&amp;nbsp;"</c>. This method is a convenience
		/// overload of <see cref="M:NBS(HtmlHelper, int)"/> with
		/// the second parameter set to <c>1</c>.
		/// </summary>
		/// <param name="htmler">The ASP.NET MVC <c>HtmlHelper</c> being extended.</param>
		/// <returns>The html string for the <c>"&amp;nbsp;"</c>.</returns>
		/// <since>1.0</since>
		public static string NBS(this HtmlHelper htmler)
		{
			return NBS(htmler, 1);
		}

		/// <summary>
		/// Creates a html anchor tag that initiates an ajax request.
		/// It is assumed that a globals js object <c>gAjaxLinksCtrl</c> 
		/// exists with a method <c>post</c> that handles the requesting by ajax.
		/// </summary>
		/// <param name="extendee">The ASP.NET MVC <c>HtmlHelper</c> being extended.</param>
		/// <param name="pText">The text of the link.</param>
		/// <param name="pUrl">The url to issue the ajax request to.</param>
		/// <returns>The html string for the link.</returns>
		/// <since>1.0</since>
		public static string AjaxActionLink(this HtmlHelper extendee, string pText, string pUrl)
		{
			var vFormat = "<a href=\"javascript:void(0)\" onclick=\"return gAjaxLinksCtrl.post('{0}');\">{1}</a>";
			var rVal = string.Format(vFormat, pUrl, pText);

			return rVal;
		}
	}
}
